package com.kfm.config;

import com.kfm.security.JwtAuthenticationFilter;
import com.kfm.security.MyAccessDeniedHandler;
import com.kfm.security.MyAuthenticationEntryPoint;
import com.kfm.security.SecurityLoginFilter;
import com.kfm.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity // 开启Spring Security
// 开启方法级别的权限控制, securedEnabled = true 开启 @Secured 注解过滤权限, prePostEnabled = true 开启 @PreAuthorize 注解过滤权限
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 配置密码加密器
     * 这里我们使用官方推荐的加密方式 BCryptPasswordEncoder
     * 如果要自定义密码加密器, 实现 PasswordEncoder 接口即可
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     *  配置安全拦截机制
     * @param http the {@link HttpSecurity}
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            //用于配置直接放行的请求
            .antMatchers("/login").permitAll()
            //其余请求都需要验证
            .anyRequest().authenticated()
            //授权码模式需要 会弹出默认自带的登录框
            .and().httpBasic().disable()
            //禁用跨站伪造
            .csrf().disable()
            // 禁用 session
            .sessionManagement().disable()
            // 异常处理
            .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler) // 处理无权限访问的异常
                .authenticationEntryPoint(myAuthenticationEntryPoint); // 未登录时的处理逻辑

        // 添加 JWT 认证过滤器
        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        // 自定义登录认证流程
        http.addFilterBefore(new SecurityLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 用户认证service - 查询数据库的逻辑
        provider.setUserDetailsService(sysUserService);
        // 设置密码加密算法
        provider.setPasswordEncoder(passwordEncoder());
        auth.authenticationProvider(provider);
    }
}
